﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using InkFx.WinControl.Core;
using InkFx.WinControl.Design;
using InkFx.WinControl.Theme;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTG = InkFx.WinControl.XIDEGroup;
using DTGS = InkFx.WinControl.XIDEGroupState;
using DTGP = InkFx.WinControl.XIDEPage;

namespace InkFx.WinControl
{
    /// <summary>
    /// 提供一个可用来创建其他控件的空控件。
    /// </summary>
    //[Designer(typeof(XIDEPanelDesigner))]
    [ToolboxItem(true), ToolboxBitmap(typeof(XIDEPanel), "Resources.Toolbox.XIDEPanel.png")]
    //[TechSupport("http://ink-fx.com/SDK/InkFx.WinControl/XIDEPanel/")]
    public partial class XIDEPanel : XIDEUserControl
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public XIDEPanel()
        {
            this.Name = XIDEPanel.NewName("idePanel");
            base.Padding = Padding.Empty;
            base.Margin = Padding.Empty;

            Tools.LogDebug(string.Format("XIDEPanel 创建: Name='{0}' Type='{1}' ", this.Name, Tools.GetKnowTypeName(this.GetType())));
        }



        #region  字 段 属 性

        /// <summary>
        /// 内部字段
        /// </summary>
        protected internal XIDEGroup m_BakActiveGroup = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEGroup m_ActiveGroup = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected ToolTip m_ToolTip = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected ContextMenuStrip m_MenuStrip = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool m_PerformanceMode = false;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventLayoutChanged = new object();



        /// <summary>
        /// 分割线尺寸
        /// </summary>
        public const int SPLIT_SIZE = 3;
        /// <summary>
        /// 分割线移动时, 左右面板最小尺寸
        /// </summary>
        public const int SPLIT_PANEL_MIN_SIZE = 62;
        /// <summary>
        /// 当有面板折叠时, 折叠的面板在 四周的 选项卡尺寸
        /// </summary>
        public const int DOCK_TAB_SIZE = 22;
        /// <summary>
        /// 弹出面板 分割线移动时, 左右面板最小尺寸
        /// </summary>
        public const int POP_SPLIT_PANEL_MIN_SIZE = 30;
        /// <summary>
        /// 弹出面板 初始尺寸
        /// </summary>
        public const int POP_SPLIT_PANEL_INIT_SIZE = 200;
        /// <summary>
        /// 默认的 XIDEGroup 尺寸
        /// </summary>
        public const int DEFAULT_GROUP_SIZE = 200;


        /// <summary>
        /// 获取或设置控件内的空白。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }
        /// <summary>
        /// 获取或设置控件之间的空间。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual new Padding Margin
        {
            get { return base.Margin; }
            set { base.Margin = value; }
        }


        /// <summary>
        /// 当Group Frame Page 的任意布局逻辑发生改变时发生
        /// </summary>
        [CategorySkinTheme, Browsable(true), Description("当Group Frame Page 的任意布局逻辑发生改变时发生")]
        public event EventHandler LayoutChanged
        {
            add { base.Events.AddHandler(m_EventLayoutChanged, value); }
            remove { base.Events.RemoveHandler(m_EventLayoutChanged, value); }
        }



        /// <summary>
        /// IDEPanel 的 内部区域 (排除 四周的折叠区域 的区域)
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectInner
        {
            get
            {
                var size = this.Size;
                var padding = base.Padding;
                return new Rectangle(padding.Left, padding.Top, size.Width - padding.Left - padding.Right, size.Height - padding.Top - padding.Bottom);
            }
        }
        /// <summary>
        /// 获取或设置 当前激活的 XIDEGroup
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual XIDEGroup ActiveGroup
        {
            get { return m_ActiveGroup; }
            set
            {
                if (value != null && !(value.FindForm() is XIDEFloatForm)) { m_BakActiveGroup = value; }

                if (m_ActiveGroup == value) return; 
                var oldActiveGroup = m_ActiveGroup;
                m_ActiveGroup = value;

                //Console.WriteLine("Set ActiveGroup: " + oldActiveGroup + " >>> " + value);
                if (oldActiveGroup != null) { oldActiveGroup.ResetRect(); oldActiveGroup.Invalidate(); }
                if (m_ActiveGroup != null) { m_ActiveGroup.ResetRect(); m_ActiveGroup.Invalidate(); }
                //if (m_ActiveGroup != null && m_ActiveGroup.State == XIDEGroupState.Collapse) { m_ActiveGroup.DoExpand(); }
                if (m_ActiveGroup != null && !m_ActiveGroup.ContainsFocus) { m_ActiveGroup.Focus(); }

                this.OnLayoutChanged(EventArgs.Empty);
            }
        }
        /// <summary>
        /// 获取或设置 当前激活的 XIDEFrame
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public XIDEFrame ActiveFrame
        {
            get
            {
                var group = this.ActiveGroup;
                return group == null ? null : group.ActiveFrame;
            }
            set
            {
                if (value == null) return;
                var group = this.FindGroup(value);
                if (group != null) { this.ActiveGroup = group; group.ActiveFrame = value; }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual ToolTip ToolTip
        {
            get { return m_ToolTip; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual ContextMenuStrip MenuStrip
        {
            get { return m_MenuStrip; }
        }


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual bool MenuStripVisible
        {
            get { return m_MenuStrip != null && m_MenuStrip.Visible; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual System.Windows.Forms.Control MenuStripSourceControl
        {
            get { return (m_MenuStrip != null && m_MenuStrip.Visible) ? m_MenuStrip.SourceControl : null; }
        }



        /// <summary>
        /// 开启性能模式: 当窗口尺寸改变时, 将会延迟进行 窗口内的控件布局
        /// </summary>
        [CategorySkinTheme, Browsable(true), DefaultValue(false), Description("开启性能模式: 当窗口尺寸改变时, 将会延迟进行 窗口内的控件布局")]
        public virtual bool PerformanceMode
        {
            get { return m_PerformanceMode; }
            set { m_PerformanceMode = value; }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示是否显示该控件及其所有父控件。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new bool Visible
        {
            get { return base.Visible; }
            set { base.Visible = value; }
        }

        #endregion


        #region  布 局 逻 辑

        /// <summary>
        /// 内部字段
        /// </summary>
        protected int m_TransLayout = 0;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected List<XIDEGroup> m_ListGroup = new List<XIDEGroup>();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected List<XIDESplitControl> m_ListSplitControl = new List<XIDESplitControl>();


        /// <summary>
        /// 将指定的 XIDEGroup 注册到 当前 XIDEPanel 中
        /// <para>注意: 这是一个内部函数, 不建议手动调用</para>
        /// </summary>
        /// <param name="group">需要注册的 XIDEGroup</param>
        public virtual void RegGroup(XIDEGroup group)
        {
            if (group == null || group.IDEPanel != this || group.Disposing || group.IsDisposed) return;
            this.m_ListGroup.Add(group);
        }
        /// <summary>
        /// 将指定的 XIDESplitControl 注册到 当前 XIDEPanel 中
        /// <para>注意: 这是一个内部函数, 不建议手动调用</para>
        /// </summary>
        /// <param name="split">需要注册的 XIDESplitControl</param>
        public virtual void RegSplitControl(XIDESplitControl split)
        {
            if (split == null || split.IDEPanel != this || split.IsDisposed) return;
            this.m_ListSplitControl.Add(split);
        }
        /// <summary>
        /// 将指定的 XIDEGroup 从 当前 XIDEPanel 中注销
        /// <para>注意: 这是一个内部函数, 不建议手动调用</para>
        /// </summary>
        /// <param name="group">需要注销的 XIDEGroup</param>
        public virtual void UnRegGroup(XIDEGroup group)
        {
            if (group == null) return;
            this.m_ListGroup.Remove(group);
        }
        /// <summary>
        /// 将指定的 XIDESplitControl 从 当前 XIDEPanel 中注销
        /// <para>注意: 这是一个内部函数, 不建议手动调用</para>
        /// </summary>
        /// <param name="split">需要注销的 XIDESplitControl</param>
        public virtual void UnRegSplitControl(XIDESplitControl split)
        {
            if (split == null) return;
            this.m_ListSplitControl.Remove(split);
        }


        /// <summary>
        /// 开启一个布局事务, 在函数结束时 会执行最后的布局矫正
        /// <para>理论上 不使用本函数 调用布局代码, XIDEPanel 依然可以稳定运行; 但使用本函数 可以提高性能 并且在批量布局时 可以避免临时资源的提前释放 而导致的各种非预期布局结果</para>
        /// <para>比如: 不包含任何Frame的Group 会在布局完成后被删除; 如果此时 没有使用本函数 则会导致 该Group被提前删除, 后续对该 Group 追加 Frame 也无法挽回这个Group (后续追加的 Frame 也无法被显示)</para>
        /// </summary>
        /// <param name="action">需要执行的布局</param>
        public void TransLayout(EmitAction action)
        {
            if (action == null) return;
            try
            {
                //Console.WriteLine("XIDEPanel.TransLayout(EmitAction action)");
                this.HideToolTip();
                m_TransLayout = m_TransLayout + 1;
                //this.SuspendLayout();

                //Invoke((ThreadStart)(() => action()));
                action();
            }
            catch (Exception ex) { MessageBox.Show(ex.ToString()); }
            finally
            {
                //this.ResumeLayout();
                m_TransLayout = m_TransLayout - 1;

                if (m_TransLayout < 0) throw new Exception("TransLayout 同步参数错误: " + m_TransLayout);
                if (m_TransLayout == 0) { this.TryDestroySplits(); this.TryDestroyGroups(); this.ResetLayout(); }
            }
        }

        /// <summary>
        /// 尝试执行 多余SplitControl的释放
        /// </summary>
        protected virtual void TryDestroySplits()
        {
            //Console.WriteLine("XIDEPanel.TryDestroySplits()");

            var groups = this.GetListGroup();
            if (groups.Count <= 0) { m_ListSplitControl.Clear(); return; }

            int tick = 0;
            EmitAction<XIDESplitPanel, XIDESplitControl> func = null;
            func = (parent, split) =>
            {
                var child1 = split.Panel1.Child;
                var child2 = split.Panel2.Child;
                if ((child1 is XIDEGroup) && ((XIDEGroup)child1).IsDisposed) child1 = null;
                if ((child2 is XIDEGroup) && ((XIDEGroup)child2).IsDisposed) child2 = null;
                if ((child1 is XIDESplitControl) && ((XIDESplitControl)child1).IsDisposed) child1 = null;
                if ((child2 is XIDESplitControl) && ((XIDESplitControl)child2).IsDisposed) child2 = null;


                if (child1 is XIDESplitControl) { func(split.Panel1, (XIDESplitControl)child1); }
                if (child2 is XIDESplitControl) { func(split.Panel2, (XIDESplitControl)child2); }

                child1 = split.Panel1.Child;
                child2 = split.Panel2.Child;
                if ((child1 is XIDEGroup) && ((XIDEGroup)child1).IsDisposed) child1 = null;
                if ((child2 is XIDEGroup) && ((XIDEGroup)child2).IsDisposed) child2 = null;
                if ((child1 is XIDESplitControl) && ((XIDESplitControl)child1).IsDisposed) child1 = null;
                if ((child2 is XIDESplitControl) && ((XIDESplitControl)child2).IsDisposed) child2 = null;

                var center1 = split.Panel1.IsCenter;
                var center2 = split.Panel2.IsCenter;
                if (child1 == null && child2 == null && !center1 && !center2) { if (parent != null) { parent.IsCenter = (center1 || center2); } split.Dispose(); tick++; return; }

                if (center1 && child2 == null) { if (parent != null) { parent.IsCenter = true; parent.SetChild(child1); } split.Dispose(); tick++; return; }
                if (center2 && child1 == null) { if (parent != null) { parent.IsCenter = true; parent.SetChild(child2); } split.Dispose(); tick++; return; }

                if (child2 == null && !center2) { if (parent != null) { parent.SetChild(child1); } split.Dispose(); tick++; return; }
                if (child1 == null && !center1) { if (parent != null) { parent.SetChild(child2); } split.Dispose(); tick++; return; }
            };

            var splitOut = this.FindOuterSplit();
            if (splitOut != null) func(null, splitOut);

            if (tick >= 1) TryDestroySplits();
        }
        /// <summary>
        /// 尝试执行 多余Group的释放
        /// </summary>
        protected virtual void TryDestroyGroups()
        {
            //Console.WriteLine("XIDEPanel.TryDestroyGroups()");

            var listD = new List<XIDEGroup>();
            var groups0 = this.GetListGroup();
            var groups1 = new List<XIDEGroup>();
            foreach (var ctrl in this.Controls) { if (ctrl is XIDEGroup) { groups1.Add((XIDEGroup)ctrl); } }

            var groups2 = groups1.FindAll(x => !groups0.Contains(x));
            listD.AddRange(groups2);

            int tick = 0;
            foreach (var group in groups0)
            {
                if (group == null) continue;
                if (group.Disposing || group.IsDisposed) listD.Add(group);
                if (group.ListPage == null || group.ListPage.Count <= 0) { listD.Add(group); }
            }

            foreach (var group in listD)
            {
                group.BaseParent = null;
                ((System.Windows.Forms.Control)group).Controls.Clear();
                group.Dispose();
                m_ListGroup.Remove(group);
                tick++;
            }

            if (tick >= 1) TryDestroyGroups();
        }

        /// <summary>
        /// 当Group Frame Page 的任意布局逻辑发生改变时发生
        /// </summary>
        /// <param name="e"></param>
        protected internal virtual void OnLayoutChanged(EventArgs e)
        {
            if (!this.IsHandleCreated || this.Disposing || this.IsDisposed) return;

            Task.SetDelay(m_Layout2Locker.GetHashCode(), () => Invoke((ThreadStart)(() =>
            {
                if (!this.IsHandleCreated || this.Disposing || this.IsDisposed) return;
                EventHandler handler = base.Events[m_EventLayoutChanged] as EventHandler;
                if (handler != null) handler(this, e);
            })), 1000);
        }

        #endregion


        #region  逻 辑 函 数

        /// <summary>
        /// 查找指定的 XIDEFrame 所属的 XIDEGroup
        /// <para>提示: XIDEPanel 包含 多个XIDEGroup, 一个 XIDEGroup 包含多个 XIDEGroupPage, 一个 XIDEGroupPage 对应一个 XIDEFrame</para>
        /// </summary>
        /// <param name="frame">需要查找的 XIDEFrame</param>
        /// <returns>所属的 XIDEGroup</returns>
        public virtual XIDEGroup FindGroup(XIDEFrame frame)
        {
            if (frame == null || frame.Disposing || frame.IsDisposed) return null;

            var listGroup = this.GetListGroup();
            foreach (var group in listGroup)
                foreach (var page in group.ListPage)
                    if (page.Frame == frame) return group;
            
            return null;
        }
        /// <summary>
        /// 查找指定的 XIDEGroupPage 所属的 XIDEGroup
        /// <para>提示: XIDEPanel 包含 多个XIDEGroup, 一个 XIDEGroup 包含多个 XIDEGroupPage, 一个 XIDEGroupPage 对应一个 XIDEFrame</para>
        /// </summary>
        /// <param name="page">需要查找的 XIDEGroupPage</param>
        /// <returns>所属的 XIDEGroup</returns>
        public virtual XIDEGroup FindGroup(XIDEPage page)
        {
            if (page == null || page.Frame == null) return null;

            var frame = page.Frame;
            if (frame == null || frame.Disposing || frame.IsDisposed) return null;

            var group = page.Group;
            if (group != null && !group.Disposing && !group.IsDisposed && frame.Parent == group) return group;

            var listGroup = this.GetListGroup();
            foreach (var group2 in listGroup)
                foreach (var page2 in group2.ListPage)
                    if (page2 == page) return group2;

            return null;
        }
        /// <summary>
        /// 查找指定的 SplitterPanel 所属的 XIDEGroup
        /// </summary>
        /// <param name="panel">需要查找的 SplitterPanel</param>
        /// <returns>所属的 XIDEGroup</returns>
        public virtual XIDEGroup FindGroup(InkFx.WinControl.XIDESplitPanel panel)
        {
            if (panel == null || panel.IsDisposed) return null;

            var group = panel.Group;
            if (group != null && !group.Disposing && !group.IsDisposed) return group;
            return null;
        }








        /// <summary>
        /// 获取当前 XIDEPanel 所包含的所有 XIDESplitControl集合 副本
        /// <para>对返回集合的成员增删, 不会影响任何逻辑</para>
        /// </summary>
        /// <returns>XIDESplitControl集合</returns>
        public virtual List<XIDESplitControl> GetListSplit()
        {
            //ReleaseLayout(); //这行代码会影响布局
            m_ListSplitControl.RemoveAll(x => x.IDEPanel != this || x.IsDisposed);
            var list = new List<XIDESplitControl>(m_ListSplitControl);
            return list;
        }
        /// <summary>
        /// 获取当前 XIDEPanel 所包含的所有 XIDEGroup集合 副本
        /// <para>对返回集合的成员增删, 不会影响任何逻辑</para>
        /// </summary>
        /// <returns>XIDEGroup集合</returns>
        public virtual List<XIDEGroup> GetListGroup()
        {
            m_ListGroup.RemoveAll(x => x.IDEPanel != this || x.Disposing || x.IsDisposed);
            var list = new List<XIDEGroup>();
            list.AddRange(m_ListGroup);
            return list;
        }
        /// <summary>
        /// 获取当前 XIDEPanel 所包含的所有 XIDEFrame集合 副本
        /// <para>对返回集合的成员增删, 不会影响任何逻辑</para>
        /// </summary>
        /// <returns>XIDEFrame集合</returns>
        public virtual List<XIDEFrame> GetListFrame()
        {
            List<XIDEGroup> listGroup = GetListGroup();
            if (listGroup == null) return null;

            var list = new List<XIDEFrame>();
            foreach (var group in listGroup) { foreach (var page in group.ListPage) { if (page.Frame != null && !page.Frame.Disposing && !page.Frame.IsDisposed) { list.Add(page.Frame); } } }
            return list;
        }


        /// <summary>
        /// 主要函数, 将指定的 XIDEFrame 附着到 当前 XIDEPanel 中, 并返回 XIDEGroup
        /// </summary>
        /// <param name="frame">需要附着的 XIDEFrame</param>
        /// <param name="align">XIDEFrame的附着的方位</param>
        /// <returns>包含此 XIDEFrame 的 XIDEGroup</returns>
        public virtual XIDEGroup DoDock(XIDEFrame frame, DA align)
        {
            return DoDock(frame, align, DTGS.Expand);
        }
        /// <summary>
        /// 主要函数, 将指定的 XIDEFrame 附着到 当前 XIDEPanel 中, 并返回 XIDEGroup
        /// </summary>
        /// <param name="frame">需要附着的 XIDEFrame</param>
        /// <param name="align">XIDEFrame的附着的方位</param>
        /// <param name="state">XIDEGroup的初始状态</param>
        /// <returns>包含此 XIDEFrame 的 XIDEGroup</returns>
        public virtual XIDEGroup DoDock(XIDEFrame frame, DA align, DTGS state)
        {
            if (frame == null) throw new ArgumentNullException("frame");
            if (align == DA.None) throw new ArgumentOutOfRangeException("align", "在XIDEFrame执行附着时 XIDEAlignment.None 无效");
            if (state == DTGS.Popup || state == DTGS.Dispose) throw new ArgumentOutOfRangeException("state", "在XIDEFrame执行附着时 XIDEGroupState.Popup 或 XIDEGroupState.Dispose 无效");

            XIDEGroup result = null;
            this.TransLayout(() =>
            {
                DoRemove(frame);
                XIDEGroup group = new XIDEGroup(this, align);
                group.AppendPage(frame);


                var group2 = DoDock(group, align);
                if (group2 != null && state != DTGS.Expand)
                {
                    if (state == DTGS.Float) group2.DoFloat();
                    else if (state == DTGS.Collapse) group2.DoCollapse();
                    //else if (state == DTGS.Popup) group2.DoPopup();
                }

                result = group2;
                return;
            });

            return result;
        }
        /// <summary>
        /// 将指定的 XIDEGroup 附着到 当前 XIDEPanel 中, 并返回 XIDEGroup (与参数group其实是同一个对象)
        /// </summary>
        /// <param name="group">需要附着的 XIDEGroup</param>
        /// <param name="align">XIDEGroup的附着的方位</param>
        /// <returns>返回 XIDEGroup(与参数group其实是同一个对象)</returns>
        public virtual XIDEGroup DoDock(XIDEGroup group, DA align)
        {
            if (group == null) throw new ArgumentNullException("group");

            XIDEGroup result = null;
            this.TransLayout(() =>
            {
                group.ReleaseSplitPanel();

                //var spilts = this.GetListSplit();
                //var groups = this.GetListGroup();

                if (align == DA.Center)
                {
                    #region  附着到 中央面板

                    var groupC = this.FindCenterGroup();
                    if (groupC == group) groupC = null;
                    if (groupC != null) { result = groupC.DoDock(group, DA.Center); return; }
                    else
                    {
                        group.m_Alignment = DA.Center;
                        group.m_State = DTGS.Expand;
                        group.BaseParent = this;

                        var panelC = this.FindCenterPanel();
                        if (panelC != null) { panelC.SetChild(group); }
                        else { group.Bounds = this.RectInner; }

                        group.Focus();
                        result = group;
                        return;
                    }

                    #endregion
                }
                else
                {
                    #region  执行拆分

                    group.m_Alignment = align;
                    var splitOut = this.FindOuterSplit();
                    if (splitOut != null) { XIDESplitControl.DoSplit(splitOut, group, align); }
                    else
                    {
                        var groupOut = this.FindOuterGroup();
                        if (groupOut == group) groupOut = null;
                        var split = new XIDESplitControl(this);
                        split.IsHorizontal = (align == DA.Top || align == DA.Bottom);
                        if (align == DA.Right || align == DA.Bottom) { split.Panel2.SetChild(group); split.Panel1.SetChild(groupOut); split.Panel1.IsCenter = true; }
                        else { split.Panel1.SetChild(group); split.Panel2.SetChild(groupOut); split.Panel2.IsCenter = true; }
                    }

                    group.Focus();
                    result = group;
                    return;

                    #endregion
                }
            });

            return result;
        }


        /// <summary>
        /// 主要函数, 从当前 XIDEPanel 中 移除指定的 XIDEFrame
        /// </summary>
        /// <param name="frame">执行移除的 XIDEFrame</param>
        public virtual void DoRemove(XIDEFrame frame)
        {
            if (frame == null) return;
            var group = FindGroup(frame);
            if (group != null) { group.RemovePage(frame); }
        }
        /// <summary>
        /// 主要函数, 从当前 XIDEPanel 中 移除指定的 XIDEPage
        /// </summary>
        /// <param name="page">执行移除的 XIDEPage</param>
        public virtual void DoRemove(XIDEPage page)
        {
            if (page == null) return;
            var group = FindGroup(page);
            if (group != null) { group.RemovePage(page); }
        }
        /// <summary>
        /// 主要函数, 从当前 XIDEPanel 中 移除指定的 XIDEGroup
        /// </summary>
        /// <param name="group">执行移除的 XIDEGroup</param>
        public virtual void DoRemove(XIDEGroup group)
        {
            if (group == null) return;
            group.DoCloseAll();
        }



        /// <summary>
        /// 内部函数, 在 XIDEGroup 执行完 拖拽附着操作后 触发此函数
        /// </summary>
        /// <param name="group">完成附着的XIDEGroup</param>
        /// <param name="e">执行附着的参数</param>
        public virtual void OnFloatDock(XIDEGroup group, XIDETipEventArgs e)
        {
            if (group == null || e == null) return;
            group.ReleaseSplitPanel();

            #region  在Group上拆分

            if (e.Group != null && e.TipLayout != null)
            {
                this.TransLayout(() => e.Group.DoDock(group, e.Alignment));
            }

            #endregion

            #region  四边区域扩展

            else if (e.TipArea != null)
            {
                this.TransLayout(() => this.DoDock(group, e.TipArea.Align));
            }

            #endregion
        }

        #endregion










        #region  重 置 布 局



        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool m_ResetLayout = false;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly object m_LayoutLocker = new object();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly object m_Layout2Locker = new object();


        /// <summary>
        /// 内部字段
        /// </summary>
        protected Size m_IconSize = new Size(16, 16);
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Size m_CloseSize = new Size(17, 17);

        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectContent = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectTop = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectBottom = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectLeft = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectRight = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly Hash<XIDEPage, XIDEPagePRect> m_HashPageRectT = new Hash<XIDEPage, XIDEPagePRect>();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly Hash<XIDEPage, XIDEPagePRect> m_HashPageRectB = new Hash<XIDEPage, XIDEPagePRect>();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly Hash<XIDEPage, XIDEPagePRect> m_HashPageRectL = new Hash<XIDEPage, XIDEPagePRect>();
        /// <summary>
        /// 内部字段
        /// </summary>
        protected readonly Hash<XIDEPage, XIDEPagePRect> m_HashPageRectR = new Hash<XIDEPage, XIDEPagePRect>();


        /// <summary>
        /// XIDEPanel 全部显示的主区域
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectMain
        {
            get { return new Rectangle(Point.Empty, this.Size); }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectContent
        {
            get { return m_RectContent; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectTop
        {
            get { return m_RectTop; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectBottom
        {
            get { return m_RectBottom; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectLeft
        {
            get { return m_RectLeft; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectRight
        {
            get { return m_RectRight; }
        }



        /// <summary>
        /// 选项卡的图标的尺寸
        /// </summary>
        [CategorySkinTheme, Browsable(true), DefaultValue(typeof(Size), "16, 16"), Description("选项卡的图标的尺寸"), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), RefreshProperties(RefreshProperties.All)]
        public virtual Size IconSize
        {
            get { return m_IconSize; }
            set { m_IconSize = value; }
        }
        /// <summary>
        /// 选项卡的关闭按钮的尺寸 (下拉列表的按钮尺寸复用的此属性)
        /// </summary>
        [CategorySkinTheme, Browsable(true), DefaultValue(typeof(Size), "17, 17"), Description("选项卡的关闭按钮的尺寸 (下拉列表的按钮尺寸复用的此属性)"), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), RefreshProperties(RefreshProperties.All)]
        public virtual Size CloseSize
        {
            get { return m_CloseSize; }
            set { m_CloseSize = value; }
        }





        /// <summary>
        /// 刷新当前 XIDEPanel 中所有控件的全部布局
        /// </summary>
        public virtual void ResetLayout()
        {
            if (m_ResetLayout) return;

            try
            {
                m_ResetLayout = true;

                this.ResetRect();

                #region  调用子级的 ResetLayout()

                //var express = Win32API.GetFormLayout(this);
                //Console.WriteLine(express);
                //Console.WriteLine("--------------------------");

                if (this.PerformanceMode && !InkFx.WinControl.Form.IsDesignMode)
                {
                    Task.SetDelay(m_LayoutLocker.GetHashCode(), () => Invoke((ThreadStart)(() =>
                    {
                        var split = this.FindOuterSplit();
                        if (split != null) split.Bounds = this.RectInner;
                        else
                        {
                            var group = this.FindOuterGroup();
                            if (group != null) group.Bounds = this.RectInner; 
                        }
                    })), 250);
                }
                else
                {
                    var split = this.FindOuterSplit();
                    if (split != null) split.Bounds = this.RectInner;
                    else
                    {
                        var group = this.FindOuterGroup();
                        if (group != null) group.Bounds = this.RectInner;
                    }
                }

                #endregion


                this.OnLayoutChanged(EventArgs.Empty);

                #region  重置 ReSetWindowPos

                var listSplit = this.GetListSplit();
                var listGroup = this.GetListGroup();
                var listFrame = this.GetListFrame();
                //var center = this.CenterPanel;


                if (listSplit != null) { foreach (var split in listSplit) { split.ResetRect(); /*Win32API.ReSetWindowPos(split.Handle);*/ } }
                if (listGroup != null) { foreach (var group in listGroup) { var state = group.State; if (state == DTGS.Expand || state == DTGS.Float || state == DTGS.Popup) { group.Visible = true; } group.ResetRect(); /*if (group.Visible) { Win32API.ReSetWindowPos(group.Handle); }*/ } }
                if (listFrame != null) { foreach (var frame in listFrame) { /*if (frame.Visible) { Win32API.ReSetWindowPos(frame.Handle); }*/ } }
                //if (center != null) { Win32API.ReSetWindowPos(center.Handle); }

                #endregion

                this.Invalidate();
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "XIDEPanel 执行 ResetLayout() 发生错误"); }
            finally { m_ResetLayout = false; }
        }

        /// <summary>
        /// 计算当前 XIDEPanel 的重绘区域
        /// </summary>
        public virtual void ResetRect()
        {
            var size = this.Size;
            var rect = this.RectMain; //this.ClientRectangle; this.DisplayRectangle; //todo: ClientRectangle 和 DisplayRectangle 都是错误的, 需要批量检查

            const int dock = DOCK_TAB_SIZE;
            const int padding = XIDEPanel.SPLIT_SIZE;

            var listGroup = this.GetListGroup();
            var listTop = listGroup.FindAll(x => x.Alignment == XIDEAlignment.Top && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listBottom = listGroup.FindAll(x => x.Alignment == XIDEAlignment.Bottom && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listLeft = listGroup.FindAll(x => x.Alignment == XIDEAlignment.Left && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listRight = listGroup.FindAll(x => x.Alignment == XIDEAlignment.Right && (x.State == DTGS.Collapse || x.State == DTGS.Popup));



            #region  计算 主区域
            
            var top2 = ((listTop.Count >= 1) ? dock + padding : padding);
            var bottom2 = ((listBottom.Count >= 1) ? dock + padding : padding);
            var left2 = ((listLeft.Count >= 1) ? dock + padding : padding);
            var right2 = ((listRight.Count >= 1) ? dock + padding : padding);

            base.Padding = new Padding(left2, top2, right2, bottom2);
            m_RectContent = new Rectangle(rect.X + left2, rect.Y + top2, rect.Width - left2 - right2, rect.Height - top2 - bottom2);

            m_RectLeft = (listLeft.Count <= 0) ? Rectangle.Empty : new Rectangle(rect.X, rect.Y + top2, dock, rect.Height - top2 - bottom2);
            m_RectRight = (listRight.Count <= 0) ? Rectangle.Empty : new Rectangle(rect.Right - dock, rect.Y + top2, dock, rect.Height - top2 - bottom2);
            m_RectTop = (listTop.Count <= 0) ? Rectangle.Empty : new Rectangle(rect.X + left2, rect.Y, rect.Width - left2 - right2, dock);
            m_RectBottom = (listBottom.Count <= 0) ? Rectangle.Empty : new Rectangle(rect.X + left2, rect.Bottom - dock, rect.Width - left2 - right2, dock);

            //Console.WriteLine(this.Padding);

            #endregion


            #region  计算折叠选项

            var hashT = ResetPageRect(DA.Top, listTop, m_RectTop);
            var hashB = ResetPageRect(DA.Bottom, listBottom, m_RectBottom);
            var hashL = ResetPageRect(DA.Left, listLeft, m_RectLeft);
            var hashR = ResetPageRect(DA.Right, listRight, m_RectRight);

            m_HashPageRectT.Clear();
            m_HashPageRectB.Clear();
            m_HashPageRectL.Clear();
            m_HashPageRectR.Clear();
            if (hashT != null) { m_HashPageRectT.AddRange(hashT); }
            if (hashB != null) { m_HashPageRectB.AddRange(hashB); }
            if (hashL != null) { m_HashPageRectL.AddRange(hashL); }
            if (hashR != null) { m_HashPageRectR.AddRange(hashR); }

            #endregion

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="align">Type: XIDEAlignment</param>
        /// <param name="listGroup">Type: List&amp;lt;XIDEGroup&amp;gt;</param>
        /// <param name="rect">Type: Rectangle</param>
        /// <returns></returns>
        protected virtual Hash<XIDEPage, XIDEPagePRect> ResetPageRect(XIDEAlignment align, List<XIDEGroup> listGroup, Rectangle rect)
        {
            if (rect.Width <= 0 || rect.Height <= 0) return null;
            if (align != DA.Top && align != DA.Bottom && align != DA.Left && align != DA.Right) return null;
            if (listGroup == null || listGroup.Count <= 0) return null;

            var font = this.Font;
            var iconSize = this.IconSize;
            //var closeSize = this.CloseSize;
            var hash = new Hash<XIDEPage, XIDEPagePRect>();


            if (align == DA.Top)
            {
                #region  Top

                int x = rect.X;
                int y = rect.Y;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        var icon = page.Icon;
                        var showIcon = !GUIHelper.ImageIsDisposed(icon);
                        var textSize = GUIHelper.GetStringPixel(page.Text, font);
                        var rect2 = new Rectangle(x, y, 3 + (showIcon ? (iconSize.Width + 3) : 0) + textSize.Width + 3, rect.Height);
                        var rectIcon2 = (!showIcon) ? Rectangle.Empty : new Rectangle(rect2.X + 3, rect2.Y + (rect2.Height - iconSize.Height) / 2, iconSize.Width, iconSize.Height);
                        var rectText2 = new Rectangle((showIcon ? rectIcon2.Right : rect2.X) + 3, rect2.Y, textSize.Width, rect.Height);
                        x = x + rect2.Width;
                        hash[page] = new XIDEPagePRect(page, rect2, rectIcon2, rectText2);
                    }
                    x = x + 1;
                }

                #endregion
            }
            else if (align == DA.Bottom)
            {
                #region Bottom

                int x = rect.X;
                int y = rect.Y;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        var icon = page.Icon;
                        var showIcon = !GUIHelper.ImageIsDisposed(icon);
                        var textSize = GUIHelper.GetStringPixel(page.Text, font);
                        var rect2 = new Rectangle(x, y, 3 + (showIcon ? (iconSize.Width + 3) : 0) + textSize.Width + 3, rect.Height);
                        var rectIcon2 = (!showIcon) ? Rectangle.Empty : new Rectangle(rect2.X + 3, rect2.Y + (rect2.Height - iconSize.Height) / 2, iconSize.Width, iconSize.Height);
                        var rectText2 = new Rectangle((showIcon ? rectIcon2.Right : rect2.X) + 3, rect2.Y, textSize.Width, rect.Height);
                        x = x + rect2.Width;
                        hash[page] = new XIDEPagePRect(page, rect2, rectIcon2, rectText2);
                    }
                    x = x + 1;
                }

                #endregion
            }
            else if (align == DA.Left)
            {
                #region Left

                int x = rect.X;
                int y = rect.Y;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        var icon = page.Icon;
                        var showIcon = !GUIHelper.ImageIsDisposed(icon);
                        var textSize = GUIHelper.GetStringPixel(page.Text, font);
                        var rect2 = new Rectangle(x, y, rect.Width, 3 + (showIcon ? (iconSize.Height + 3) : 0) + textSize.Width + 3);
                        var rectIcon2 = (!showIcon) ? Rectangle.Empty : new Rectangle(rect2.X + (rect2.Width - iconSize.Width) / 2, rect2.Y + 3, iconSize.Width, iconSize.Height);
                        var rectText2 = new Rectangle(rect2.X, (showIcon ? rectIcon2.Bottom : rect2.Y) + 3, rect.Width, textSize.Width);
                        y = y + rect2.Height;
                        hash[page] = new XIDEPagePRect(page, rect2, rectIcon2, rectText2);
                    }
                    y = y + 1;
                }

                #endregion
            }
            else if (align == DA.Right)
            {
                #region Right

                int x = rect.X;
                int y = rect.Y;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        var icon = page.Icon;
                        var showIcon = !GUIHelper.ImageIsDisposed(icon);
                        var textSize = GUIHelper.GetStringPixel(page.Text, font);
                        var rect2 = new Rectangle(x, y, rect.Width, 3 + (showIcon ? (iconSize.Height + 3) : 0) + textSize.Width + 3);
                        var rectIcon2 = (!showIcon) ? Rectangle.Empty : new Rectangle(rect2.X + (rect2.Width - iconSize.Width) / 2, rect2.Y + 3, iconSize.Width, iconSize.Height);
                        var rectText2 = new Rectangle(rect2.X, (showIcon ? rectIcon2.Bottom : rect2.Y) + 3, rect.Width, textSize.Width);
                        y = y + rect2.Height;
                        hash[page] = new XIDEPagePRect(page, rect2, rectIcon2, rectText2);
                    }
                    y = y + 1;
                }

                #endregion
            }

            return hash;
        }





        #endregion


        #region  弹 出 菜 单 或 气 泡


        /// <summary>
        /// 在执行的位置显示一个 气泡提示
        /// </summary>
        /// <param name="group">气泡对应的 Group</param>
        /// <param name="page">气泡对应的 Page</param>
        /// <param name="text">需要提示的文本</param>
        /// <param name="point">当前光标相对 Group 的位置</param>
        public virtual void ShowToolTip(XIDEGroup group, XIDEPage page, string text, Point point)
        {
            try
            {
                if (Tools.IsNullOrWhiteSpace(text)) return;
                if (m_ToolTip == null/* || m_ToolTip.Text == text*/) return;

                var text2 = text + " ";
                var rect = page.RectRealTitle;
                var point2 = new Point(rect.X + 5, rect.Bottom + 5);
                m_ToolTip.Show(text2, group, point2); //point 这里不用 point
            }
            catch (Exception ex) { Tools.LogWarn(ex); }
        }
        /// <summary>
        /// 关闭 气泡提示
        /// </summary>
        public virtual void HideToolTip()
        {
            try
            {
                if (m_ToolTip == null) return;
                m_ToolTip.Hide(this);
            }
            catch (Exception ex) { Tools.LogWarn(ex); }
        }



        /// <summary>
        /// 执行 右键弹窗菜单, 不建议改写本函数: 建议改写 CreateTabMenuItems(*) 菜单选项函数 和 OoMenuStripClick(*) 菜单执行函数
        /// </summary>
        /// <param name="group">触发菜单的 Group</param>
        /// <param name="page">触发菜单的 Page</param>
        /// <param name="point">触发菜单时, 相对于 Group 的坐标</param>
        /// <param name="items">需要显示的菜单项</param>
        public virtual void OpenMenuStrip(XIDEGroup group, XIDEPage page, Point point, List<XIDEMenuItem> items)
        {
            if (items == null || items.Count <= 0) return;
            if (m_MenuStrip == null || m_MenuStrip.Disposing || m_MenuStrip.IsDisposed) return;

            m_MenuStrip.Items.Clear();
            foreach (var item1 in items)
            {
                var item2 = new ToolStripMenuItem(item1.Text, item1.Icon);
                item2.Name = item1.Name;
                item2.Enabled = item1.Enabled;
                item2.Tag = new XIDEMenuItemInfo(group, page, item1);
                m_MenuStrip.Items.Add(item2);
            }

            m_MenuStrip.Show(group, point);
        }

        /// <summary>
        /// 通过指定的 TabGroup, 计算出 该TabGroup 即将显示的 右键菜单选项
        /// </summary>
        /// <param name="group">Type: XIDEGroup</param>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="point">Type: Point</param>
        /// <param name="isRightButton">Type: bool</param>
        /// <returns></returns>
        public virtual List<XIDEMenuItem> CreateMenuItems(XIDEGroup group, XIDEPage page, Point point, bool isRightButton)
        {
            var items = new List<XIDEMenuItem>();

            if (!isRightButton)
            {
                //点击 下拉菜单 按钮
                if (group.IsCenterLayout())
                {
                    foreach (var page2 in group.ListPage) { items.Add(new XIDEMenuItem("DoFocusPage", page2.Text, true, page2)); }
                    items.Sort((x, y) => StringComparer.CurrentCultureIgnoreCase.Compare(x.Text, y.Text));
                }
                else
                {
                    items.Add(new XIDEMenuItem("DoFloat", "浮动", (group.State != XIDEGroupState.Float)));
                    items.Add(new XIDEMenuItem("DoExpand", "展开", (group.State != XIDEGroupState.Expand)));
                    items.Add(new XIDEMenuItem("DoCollapse", "折叠", (group.State != XIDEGroupState.Collapse)));
                    items.Add(new XIDEMenuItem("DoCloseActive", "关闭", true));
                }
            }
            else
            {
                //在标题区 点击右键
                if ((group.Alignment == DA.Center))
                {
                    if ((group.State == XIDEGroupState.Expand))
                    {
                        items.Add(new XIDEMenuItem("DoFloatActive", "浮动", (group.State != XIDEGroupState.Float)));
                        items.Add(new XIDEMenuItem("DoExpand", "展开", false));
                        items.Add(new XIDEMenuItem("DoCloseActive", "关闭", true));
                        items.Add(new XIDEMenuItem("DoCloseAll", "关闭全部", true));
                    }
                    else
                    {
                        items.Add(new XIDEMenuItem("DoFloatActive", "浮动", false));
                        items.Add(new XIDEMenuItem("DoExpand", "展开", true));
                        items.Add(new XIDEMenuItem("DoCloseActive", "关闭", true));
                    }
                }
                else if (group.RectTitle.Contains(point))
                {
                    items.Add(new XIDEMenuItem("DoFloat", "浮动", (group.State != XIDEGroupState.Float)));
                    items.Add(new XIDEMenuItem("DoExpand", "展开", (group.State != XIDEGroupState.Expand)));
                    items.Add(new XIDEMenuItem("DoCollapse", "折叠", (group.State != XIDEGroupState.Collapse)));
                    items.Add(new XIDEMenuItem("DoCloseActive", "关闭", true));
                }
            }
            
            return items;
        }

        /// <summary>
        /// 执行菜单选项的单击触发
        /// </summary>
        /// <param name="group">触发菜单的 Group</param>
        /// <param name="page">触发菜单的 Page</param>
        /// <param name="item">触发菜单的 菜单项</param>
        public virtual void OnMenuStripClick(XIDEGroup group, XIDEPage page, XIDEMenuItem item)
        {
            if (item.Name == "DoFocusPage")
            {
                //右键菜单 选中溢出的 Page
                var page2 = item.Tag as XIDEPage;
                if (page2 != null)
                {
                    if (page2.RectRealTitle.Width <= 0) group.SetActiveFirstPage(page2);
                    else group.SetActivePage(page2);
                }
            }
            else if (item.Name == "DoFloat") { group.DoFloat(); }               //将选中的Group以窗体模式悬浮
            else if (item.Name == "DoFloatActive") { group.DoFloatActive(); }   //将选中的Group的激活Page以窗体模式悬浮
            else if (item.Name == "DoExpand") { group.DoExpand(); }             //展开选中的Group
            else if (item.Name == "DoCollapse") { group.DoCollapse(); }         //折叠选中的Group
            else if (item.Name == "DoCloseActive") { group.DoCloseActive(); }   //关闭选中的Group的激活Page
            else if (item.Name == "DoCloseAll") { group.DoCloseAll(); }         //关闭选中的Group的全部Page
        }
        
        /// <summary>
        /// 弹出菜单单击 选项后发生
        /// </summary>
        /// <param name="sender">弹出菜单</param>
        /// <param name="e">菜单的单击选项</param>
        protected virtual void MenuStripItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            var item1 = e.ClickedItem;
            var info = item1 == null ? null : item1.Tag as XIDEMenuItemInfo;
            if (info != null) OnMenuStripClick(info.Group, info.Page, info.Item);
        }

        #endregion


        #region  继 承 改 写

        /// <summary>
        /// 引发 System.Windows.Forms.Control.HandleCreated 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);

            if (!DesignMode)
            {
                m_ToolTip = new ToolTip();
                m_MenuStrip = new ContextMenuStrip();
                m_MenuStrip.ItemClicked += MenuStripItemClicked;
                
                this.ResetLayout();
            }
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.HandleDestroyed 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnHandleDestroyed(EventArgs e)
        {
            base.OnHandleDestroyed(e);

            if (m_ToolTip != null) { m_ToolTip.Dispose(); m_ToolTip = null; }
            if (m_MenuStrip != null) { m_MenuStrip.Dispose(); m_MenuStrip = null; }
        }

        /// <summary>
        /// 引发 System.Windows.Forms.UserControl.Load 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            //Console.WriteLine("XIDEPanel.OnLoad(EventArgs e)");

            var form = this.FindForm();
            if (form != null) form.Activated += OnFormActivated;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender">Type: object</param>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnFormActivated(object sender, EventArgs e)
        {
            if (m_BakActiveGroup != null && !m_BakActiveGroup.Disposing && !m_BakActiveGroup.IsDisposed) { this.ActiveGroup = m_BakActiveGroup; }
        }


        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;
        //        cp.ExStyle |= (int)WindowStyles.WS_CLIPCHILDREN; //此参数 会引入 另外的BUG, 此BUG将导致 100%
        //        return cp;
        //    }
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="m">Type: ref Message</param>
        protected override void WndProc(ref Message m)
        {
            //if (m.Msg == Win32Msg.WM_SIZE)
            //{
            //    Win32API.SetExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    Task.SetDelay(this.Handle.ToInt32(), () => Invoke((ThreadStart)(() =>
            //    {
            //        Console.WriteLine("Run Delay");
            //        Win32API.DelExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //        //m_Set_WS_CLIPCHILDREN = false;
            //        //base.Invalidate();
            //        base.Refresh();
            //    })), 1000);
            //}

            base.WndProc(ref m);
        }

        /// <summary>
        /// 引发 System.Windows.Forms.Control.SizeChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            if (!this.Disposing && !this.IsDisposed) { this.ResetLayout(); }

            #region  作废的代码

            //此参数 会引入 另外的BUG, 此BUG将导致 100%
            //if (this.IsHandleCreated && !this.Disposing && !this.IsDisposed)
            //{
            //    //Win32API.DelExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    //this.Invalidate();

            //    //Task.SetTimeout(() => Invoke((ThreadStart) (() =>
            //    //{
            //    //    Win32API.SetExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    //    this.Invalidate();
            //    //})), 2000);
            //}

            #endregion

            base.OnSizeChanged(e);
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseEnter 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseClick 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnClick(e);

            var rectT = this.RectTop;
            var rectB = this.RectBottom;
            var rectL = this.RectLeft;
            var rectR = this.RectRight;
            var point2 = e.Location;

            if (rectT.Width <= 0 && rectT.Height <= 0 && rectB.Width <= 0 && rectB.Height <= 0 && rectL.Width <= 0 && rectL.Height <= 0 && rectR.Width <= 0 && rectR.Height <= 0) return;
            if (!rectT.Contains(point2) && !rectB.Contains(point2) && !rectL.Contains(point2) && !rectR.Contains(point2)) return;

            var hash1 = rectT.Contains(point2) ? this.m_HashPageRectT : (rectB.Contains(point2) ? this.m_HashPageRectB : (rectL.Contains(point2) ? this.m_HashPageRectL : (rectR.Contains(point2) ? this.m_HashPageRectR : null)));
            if (hash1 == null || hash1.Count <= 0) return;
            
            var hash2 = new Hash<XIDEPage, XIDEPagePRect>();
            hash2.AddRange(hash1);

            foreach (var rect in hash2.Values)
            {
                if (rect == null) continue;
                var rect2 = rect.Rect;
                var page2 = rect.Page;
                if (page2 == null) continue;
                var group = page2.Group;
                if (group != null && !group.Disposing && !group.IsDisposed && rect2.Contains(point2)) { XIDEPopPanel.PopPage(page2); }
            }
        }
        /// <summary>
        /// 返回包含 System.ComponentModel.Component 的名称的 System.String（如果有）。不应重写此方法。
        /// </summary>
        /// <returns>包含 System.ComponentModel.Component 的名称的 System.String（如果有）；如果 System.ComponentModel.Component 未命名，则为 null。</returns>
        public override string ToString()
        {
            return "XIDEPanel: ".PadRight(30) + this.Name;
        }

        /// <summary>
        /// 释放由 System.Windows.Forms.ButtonBase 占用的非托管资源，还可以另外再释放托管资源。
        /// </summary>
        /// <param name="disposing">为 true 则释放托管资源和非托管资源；为 false 则仅释放非托管资源。</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                base.Dispose(disposing);
                Tools.LogDebug(string.Format("XIDEPanel 销毁: Name='{0}' Text='{1}' Type='{2}' ", this.Name, this.Text, Tools.GetKnowTypeName(this.GetType())));
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "可忽略的偶发错误"); }
        }


        #endregion


        #region  控 件 重 绘


        /// <summary>
        /// 引发 System.Windows.Forms.Control.Paint 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.PaintEventArgs。</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                base.OnPaint(e);
                if (this.Disposing || this.IsDisposed) return;

                var theme = this.Theme;
                var g = e.Graphics;
                var debug = false;

                if (debug)
                {
                    #region  调试重绘

                    GUIHelper.FillBack(g, Color.FromArgb(100, 255, 255, 0), this.RectMain, true);
                    GUIHelper.FillBack(g, Color.FromArgb(150, 255, 0, 255), this.RectContent, true);
                    GUIHelper.FillBack(g, Color.FromArgb(150, 0, 255, 255), this.RectTop, true);
                    GUIHelper.FillBack(g, Color.FromArgb(150, 0, 255, 255), this.RectBottom, true);
                    GUIHelper.FillBack(g, Color.FromArgb(150, 0, 255, 255), this.RectLeft, true);
                    GUIHelper.FillBack(g, Color.FromArgb(150, 0, 255, 255), this.RectRight, true);

                    foreach (var rect in m_HashPageRectT.Values) { GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.Rect, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectIcon, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectText, true); }
                    foreach (var rect in m_HashPageRectB.Values) { GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.Rect, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectIcon, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectText, true); }
                    foreach (var rect in m_HashPageRectL.Values) { GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.Rect, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectIcon, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectText, true); }
                    foreach (var rect in m_HashPageRectR.Values) { GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.Rect, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectIcon, true); GUIHelper.FillBack(g, GUIHelper.GetRandomColor(150), rect.RectText, true); }

                    #endregion
                }
                else
                {
                    #region  正式重绘

                    this.OnPaintRivetedPages(e, g, theme, DA.Top, this.RectTop, this.m_HashPageRectT.Values);
                    this.OnPaintRivetedPages(e, g, theme, DA.Bottom, this.RectBottom, this.m_HashPageRectB.Values);
                    this.OnPaintRivetedPages(e, g, theme, DA.Left, this.RectLeft, this.m_HashPageRectL.Values);
                    this.OnPaintRivetedPages(e, g, theme, DA.Right, this.RectRight, this.m_HashPageRectR.Values);

                    #endregion
                }
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "改写 XIDEPanel.OnPaint(PaintEventArgs e) 发生错误"); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="align">Type: DA</param>
        /// <param name="rectClip">Type: Rectangle</param>
        /// <param name="listRect">Type: ICollection&amp;lt;XIDEPagePRect&amp;gt;</param>
        protected virtual void OnPaintRivetedPages(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, DA align, Rectangle rectClip, ICollection<XIDEPagePRect> listRect)
        {
            if (g == null || align == DA.None || align == DA.Center) return;
            if (listRect == null) return;

            var list = new List<XIDEPagePRect>(listRect);
            if (list.Count <= 0) return;

            var enable = this.Enabled;
            g.SetClip(rectClip, CombineMode.Intersect);
            foreach (var rect in list)
            {
                if (rect == null || rect.Page == null || rect.Page.Group == null) continue;
                var page2 = rect.Page;
                var group2 = page2.Group;
                var rect2 = rect.Rect;
                var rectIcon2 = rect.RectIcon;
                var rectText2 = rect.RectText;
                OnPaintRivetedPage(e, g, theme, enable, group2, page2, align, rectClip, rect2, rectIcon2, rectText2);
            }
            g.SetClip(this.RectMain, CombineMode.Union);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="group">Type: DTG</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="align">Type: DA</param>
        /// <param name="rectClip">Type: Rectangle</param>
        /// <param name="rectPage">Type: Rectangle</param>
        /// <param name="rectIcon">Type: Rectangle</param>
        /// <param name="rectText">Type: Rectangle</param>
        protected virtual void OnPaintRivetedPage(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, DTG group, DTGP page, DA align, Rectangle rectClip, Rectangle rectPage, Rectangle rectIcon, Rectangle rectText)
        {
            var icon = page.Icon;
            OnPaintRivetedPageBack(e, g, theme, enable, group, page, align, rectClip, rectPage);
            OnPaintRivetedPageText(e, g, theme, enable, group, page, align, rectClip, rectText);
            OnPaintRivetedPageIcon(e, g, theme, enable, group, page, align, rectClip, rectIcon, icon);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="group">Type: DTG</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="align">Type: DA</param>
        /// <param name="rectClip">Type: Rectangle</param>
        /// <param name="rectPage">Type: Rectangle</param>
        protected virtual void OnPaintRivetedPageBack(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, DTG group, DTGP page, DA align, Rectangle rectClip, Rectangle rectPage)
        {
            Point point = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);
            bool hover = rectClip.Contains(point) && rectPage.Contains(point);
            bool select = XIDEPopPanel.ActivePopPage == page;
            bool press = (hover && MouseButtons == MouseButtons.Left);
            Rectangle rect = rectPage;

            int headImgV = !enable ? 3 : ((press || select) ? 2 : (hover ? 1 : 0));
            SkinBorderImage_V4 headImgV4 = null;
            if (align == DA.Top) { headImgV4 = theme.XIDEPanel_HeadTop_V4; }
            else if (align == DA.Bottom) { headImgV4 = theme.XIDEPanel_HeadBottom_V4; }
            else if (align == DA.Left) { headImgV4 = theme.XIDEPanel_HeadLeft_V4; }
            else if (align == DA.Right) { headImgV4 = theme.XIDEPanel_HeadRight_V4; }

            if (headImgV4 != null && !headImgV4.IsEmpty) { headImgV4.DrawImage(g, headImgV, rect); }


            #region  作废的代码

            //RoundStyle doundStyle = RoundStyle.None;
            //if (align == DA.Top) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Top; }
            //else if (align == DA.Bottom) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Bottom; }
            //else if (align == DA.Left) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Left; }
            //else if (align == DA.Right) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Right; }

            //Color colorPage = (press || select) ? m_FocusColor : (hover ? Color.FromArgb(100, m_FocusColor) : m_TitleColor);
            //GUIHelper.FillBack(g, rect, colorPage, enable);

            #endregion
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="group">Type: DTG</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="align">Type: DA</param>
        /// <param name="rectClip">Type: Rectangle</param>
        /// <param name="rectText">Type: Rectangle</param>
        protected virtual void OnPaintRivetedPageText(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, DTG group, DTGP page, DA align, Rectangle rectClip, Rectangle rectText)
        {
            //GUIHelper.FillBack(g, rectText, Color.FromArgb(100, Color.Cyan), enable);
            if (align == DA.Top) { GUIHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, StringFormat.GenericDefault, this.Enabled); }
            else if (align == DA.Bottom) { GUIHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, StringFormat.GenericDefault, this.Enabled); }
            else if (align == DA.Left) { GUIHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled, 90); /*270*/ }
            else if (align == DA.Right) { GUIHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled, 90); }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        /// <param name="g">Type: Graphics</param>
        /// <param name="theme">Type: ThemeXIDEPanel</param>
        /// <param name="enable">Type: bool</param>
        /// <param name="group">Type: DTG</param>
        /// <param name="page">Type: DTGP</param>
        /// <param name="align">Type: DA</param>
        /// <param name="rectClip">Type: Rectangle</param>
        /// <param name="rectIcon">Type: Rectangle</param>
        /// <param name="icon">Type: Image</param>
        protected virtual void OnPaintRivetedPageIcon(PaintEventArgs e, Graphics g, ThemeXIDEPanel theme, bool enable, DTG group, DTGP page, DA align, Rectangle rectClip, Rectangle rectIcon, Image icon)
        {
            if (!this.Enabled) icon = GUIHelper.CreateDisabledImage(icon);
            GUIHelper.DrawImageCenter(g, icon, rectIcon);
        }


        #endregion


        #region  静 态 函 数

        private static readonly Hash<int> m_HashNameTick = new Hash<int>();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name">Type: string</param>
        /// <returns></returns>
        public static string NewName(string name)
        {
            if (Tools.IsNullOrWhiteSpace(name)) return string.Empty;
            int tick = m_HashNameTick[name];
            tick = tick + 1;
            m_HashNameTick[name] = tick;
            return name + tick;
        }

        #endregion

    }

    /// <summary>
    /// 
    /// </summary>
    public class XIDEPagePRect
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="page">Type: XIDEPage</param>
        /// <param name="rect">Type: Rectangle</param>
        /// <param name="rectIcon">Type: Rectangle</param>
        /// <param name="rectText">Type: Rectangle</param>
        public XIDEPagePRect(XIDEPage page, Rectangle rect, Rectangle rectIcon, Rectangle rectText)
        {
            this.m_Page = page;
            this.m_Rect = rect;
            this.m_RectIcon = rectIcon;
            this.m_RectText = rectText;
        }

        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPage m_Page = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_Rect = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectIcon = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectText = Rectangle.Empty;

        /// <summary>
        /// 
        /// </summary>
        public XIDEPage Page { get { return m_Page; } }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle Rect { get { return m_Rect; } }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectIcon { get { return m_RectIcon; } }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectText { get { return m_RectText; } }
    }


    /// <summary>
    /// XIDEPanel 的布局信息 (此对象 用于 程序重启时 恢复布局之用)
    /// </summary>
    public class XIDELayoutInfo
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="enum">Type: XIDELayoutMode</param>
        /// <param name="ctrl">Type: XIDEGroup</param>
        public XIDELayoutInfo(XIDELayoutMode @enum, XIDEGroup ctrl)
        {
            this.Enum = @enum;
            this.Group = ctrl;
        }

        /// <summary>
        /// 
        /// </summary>
        public XIDELayoutMode Enum { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle Rect { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public XIDEGroup Group { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public XIDETipGroupRect TipRect
        {
            get
            {
                const int SIZE = XIDEPanel.SPLIT_SIZE + 28 + XIDEPanel.SPLIT_SIZE + 28 + XIDEPanel.SPLIT_SIZE + 28 + XIDEPanel.SPLIT_SIZE;
                Rectangle rect1 = this.Rect;
                Rectangle rect2 = new Rectangle(0, 0, SIZE, SIZE);
                if (rect1.Width < rect2.Width || rect1.Height < rect2.Height) return XIDETipGroupRect.Empty;
                Rectangle rect3 = new Rectangle((rect1.X) + (rect1.Width - rect2.Width) / 2, (rect1.Y) + (rect1.Height - rect2.Height) / 2, rect2.Width, rect2.Height);
                return new XIDETipGroupRect(rect3, !(Group != null && Group.State == DTGS.Expand));
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public XIDEPanel IDEPanel
        {
            get
            {
                if (Group != null && Group.IDEPanel != null) return Group.IDEPanel;
                return null;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool MouseInRect()
        {
            //var point1 = System.Windows.Forms.Control.MousePosition;
            //return Rect.Contains(point1);

            var group = this.Group;
            if (group != null)
            {
                var rect = this.Rect;
                var point1 = System.Windows.Forms.Control.MousePosition;
                var point2 = group.PointToClient(point1);
                return rect.Contains(point2);
            }
            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public XIDEAlignment MouseInTipRect()
        {
            var group = this.Group;
            if (group != null)
            {
                var point1 = System.Windows.Forms.Control.MousePosition;
                var point2 = group.PointToClient(point1);
                return TipRect.Contains(point2);
            }
            return DA.None;
        }
    }

    /// <summary>
    /// XIDEPanel 的区域信息 (一般在 移动附着 XIDEGroup 时 用于指示 附着区域)
    /// </summary>
    public class XIDEAreaInfo
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="align">Type: XIDEAlignment</param>
        /// <param name="ctrl">Type: XIDEPanel</param>
        public XIDEAreaInfo(XIDEAlignment align, XIDEPanel ctrl)
        {
            this.Align = align;
            this.IDEPanel = ctrl;
        }

        /// <summary>
        /// 
        /// </summary>
        public XIDEAlignment Align { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public XIDEPanel IDEPanel { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle Rect { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool MouseInRect()
        {
            //var point1 = System.Windows.Forms.Control.MousePosition;
            //return Rect.Contains(point1);

            var idePanel = this.IDEPanel;
            var rect = this.Rect;
            if (this.Align == DA.Center)
            {
                var rect2 = idePanel.FindCenterRect();
                rect = new Rectangle(rect2.X + rect.X, rect2.Y + rect.Y, rect.Width, rect.Height);
            }

            var point1 = System.Windows.Forms.Control.MousePosition;
            var point2 = idePanel.PointToClient(point1);
            return rect.Contains(point2);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public XIDEAlignment MouseInTipRect()
        {
            if (MouseInRect()) return Align;
            return DA.None;
        }
    }

    /// <summary>
    /// XIDEGroup 在移动附着时 的提示区域
    /// </summary>
    public struct XIDETipGroupRect
    {
        /// <summary>
        /// 
        /// </summary>
        public static readonly XIDETipGroupRect Empty = new XIDETipGroupRect();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="rect">Type: Rectangle</param>
        /// <param name="onlyCenter">Type: bool</param>
        public XIDETipGroupRect(Rectangle rect, bool onlyCenter) : this()
        {
            int swidth = 28;
            int sheight = 28;
            int split = (rect.Width - (swidth * 3)) / 4;

            RectFull = rect;
            RectCenter = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + sheight + (split * 2), swidth, sheight);

            OnlyCenter = onlyCenter;
            if (onlyCenter)
            {
                RectTop = RectBottom = RectLeft = RectRight = Rectangle.Empty;
            }
            else
            {
                RectTop = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + split, swidth, sheight);
                RectBottom = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + (sheight * 2) + (split * 3), swidth, sheight);
                RectLeft = new Rectangle(RectFull.X + split, RectFull.Y + sheight + (split * 2), swidth, sheight);
                RectRight = new Rectangle(RectFull.X + (swidth * 2) + (split * 3), RectFull.Y + sheight + (split * 2), swidth, sheight);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool OnlyCenter { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectFull { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectCenter { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectTop { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectBottom { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectLeft { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Rectangle RectRight { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int Width { get { return RectFull.Width; } }
        /// <summary>
        /// 
        /// </summary>
        public int Height { get { return RectFull.Height; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point">Type: Point</param>
        /// <returns></returns>
        public XIDEAlignment Contains(Point point)
        {
            if (RectCenter.Contains(point)) return DA.Center;
            if (RectTop.Contains(point)) return DA.Top;
            if (RectBottom.Contains(point)) return DA.Bottom;
            if (RectLeft.Contains(point)) return DA.Left;
            if (RectRight.Contains(point)) return DA.Right;
            return DA.None;
        }
    }

    /// <summary>
    /// XIDEPanel 中的 布局角色
    /// </summary>
    public enum XIDELayoutMode
    {
        /// <summary>
        /// XIDEPanel 的 中央面板
        /// </summary>
        CenterPanel,
        /// <summary>
        /// XIDEPanel 的 XIDEGroup
        /// </summary>
        Group,
        /// <summary>
        /// 纵向拆分的 分割面板
        /// </summary>
        Vertical,
        /// <summary>
        /// 横向拆分的 分割面板
        /// </summary>
        Horizontal,
    }

    /// <summary>
    /// XIDEGroup 的 布局方位
    /// </summary>
    public enum XIDEAlignment
    {
        /// <summary>
        /// 
        /// </summary>
        None,
        /// <summary>
        /// 
        /// </summary>
        Top,
        /// <summary>
        /// 
        /// </summary>
        Bottom,
        /// <summary>
        /// 
        /// </summary>
        Left,
        /// <summary>
        /// 
        /// </summary>
        Right,
        /// <summary>
        /// 
        /// </summary>
        Center,
    }

    /// <summary>
    /// XIDEGroup 在移动附着时的 事件参数
    /// </summary>
    public class XIDETipEventArgs : EventArgs
    {
        /// <summary>
        /// 
        /// </summary>
        public XIDEGroup Group;
        /// <summary>
        /// 
        /// </summary>
        public XIDEAreaInfo TipArea;
        /// <summary>
        /// 
        /// </summary>
        public XIDELayoutInfo TipLayout;
        /// <summary>
        /// 
        /// </summary>
        public XIDEAlignment Alignment;
    }

}

//namespace InkFx.WinControl.Design
//{
//    /// <summary>
//    /// 显示 &quot;技术支持&quot; 的 设计时扩展
//    /// </summary>
//    public class XIDEPanelDesigner : TechSupportSizeControlDesigner
//    {
//        //todo: System.Windows.Forms.UserControl 的 设计器 需要再次确定

//    }
//}